﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace DynamicGeometry
{
    public static class IFigureExtensions
    {
        public static void RecalculateAllDependents(this IFigure figure)
        {
            DependencyAlgorithms
                .FindDescendants(f => f.Dependents, new IFigure[] { figure })
                .Reverse()
                .ForEach(f => f.RecalculateAndUpdateVisual());
        }

        public static void RecalculateAndUpdateVisual(this IFigure figure)
        {
            figure.Recalculate();
            figure.UpdateVisual();
        }

        public static IEnumerable<Point> EnumeratePointsOnLinearFigure(this ILinearFigure figure)
        {
            var domain = figure.GetParameterDomain();
            for (double lambda = domain.Item1; lambda < domain.Item2; lambda += 0.01)
            {
                yield return figure.GetPointFromParameter(lambda);
            }
        }

        public static Point Point(this IFigure figure, int index)
        {
            return (figure.Dependencies.ElementAt(index) as IPoint).Coordinates;
        }

        public static void Move(this IEnumerable<IMovable> figures, Point offset)
        {
            foreach (var figure in figures)
            {
                figure.MoveTo(figure.Coordinates.Plus(offset));
            }
        }

        public static PointPair Line(this IFigure figure, int index)
        {
            return (figure.Dependencies.ElementAt(index) as ILine).Coordinates;
        }

        public static void RegisterWithDependencies(this IFigure figure)
        {
            if (figure == null || figure.Dependencies == null)
            {
                return;
            }
            foreach (var dependency in figure.Dependencies)
            {
                dependency.Dependents.Add(figure);
            }
        }

        public static void UnregisterFromDependencies(this IFigure figure)
        {
            if (figure == null || figure.Dependencies == null)
            {
                return;
            }
            foreach (var dependency in figure.Dependencies)
            {
                dependency.Dependents.Remove(figure);
            }
        }

        public static void ReplaceDependency(this IFigure figure, int index, IFigure newDependency)
        {
            List<IFigure> temp = new List<IFigure>(figure.Dependencies);
            if (index < 0 || index >= temp.Count)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            IFigure oldDependency = temp[index];
            oldDependency.Dependents.Remove(figure);
            temp[index] = newDependency;
            newDependency.Dependents.Add(figure);
            figure.Dependencies = temp;
        }

        public static void ReplaceDependency(this IFigure figure, IFigure oldDependency, IFigure newDependency)
        {
            figure.Dependencies = figure.Dependencies.Replace(oldDependency, newDependency).ToArray();
        }

        public static void SubstituteWith(this IFigure figure, IFigure replacement)
        {
            List<IFigure> dependents = new List<IFigure>(figure.Dependents);
            foreach (var dependent in dependents)
            {
                dependent.ReplaceDependency(figure, replacement);
            }
            replacement.Dependents.AddRange(figure.Dependents.ToArray());
            figure.Dependents.Clear();
        }

        public static void CheckConsistency(this IFigureList list)
        {
            foreach (var figure in list)
            {
                if (figure.Dependencies != null)
                {
                    foreach (var dependency in figure.Dependencies)
                    {
                        //if (!list.Contains(dependency))
                        //{
                        //    throw new Exception();
                        //}
                        if (!dependency.Dependents.Contains(figure))
                        {
                            throw new Exception();
                        }
                    }
                }
                if (figure.Dependents != null)
                {
                    foreach (var dependent in figure.Dependents)
                    {
                        //if (!list.Contains(dependent))
                        //{
                        //    throw new Exception();
                        //}

                        if (!dependent.Dependencies.Contains(figure))
                        {
                            throw new Exception();
                        }
                    }
                }
            }
        }
    }
}
